package com.pine.dbant.core.service.impl;

import com.pine.dbant.core.entity.Directory;
import com.pine.dbant.core.entity.Relation;
import com.pine.dbant.core.mapper.DirectoryMapper;
import com.pine.dbant.core.model.RelationType;
import com.pine.dbant.core.model.dto.DirectoryDTO;
import com.pine.dbant.core.model.vo.DirTreeVO;
import com.pine.dbant.core.service.ConnectionService;
import com.pine.dbant.core.service.DirectoryService;
import com.pine.dbant.core.service.RelationService;
import com.pine.dbant.core.utils.TreeUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class DirectoryServiceImpl implements DirectoryService {
    @Autowired
    private DirectoryMapper directoryMapper;
    @Autowired
    private RelationService relationService;
    @Autowired
    private ConnectionService connectionService;

    @Override
    public List<DirTreeVO> getConnTree() {
        List<DirTreeVO> jobDirVOS = this.directoryMapper.getDirTree();
        List<DirTreeVO> tempJobDirVOS = this.directoryMapper.getConnTree();
        List<DirTreeVO> cons = tempJobDirVOS.stream().filter(dirTreeVO -> dirTreeVO.getType().equals(DirTreeVO.Type.CONN)).collect(Collectors.toList());
        List<DirTreeVO> trees = TreeUtils.getTreeList(null, jobDirVOS);
        getConnInfo(trees,cons.stream().filter(dirTreeVO -> dirTreeVO.getParentId()!=null).collect(Collectors.toList()));
        trees.addAll(cons.stream().filter(dirTreeVO -> dirTreeVO.getParentId()==null).collect(Collectors.toList()));
        return trees;
    }

    private void getConnInfo(List<DirTreeVO> trees, List<DirTreeVO> cons) {
        for (DirTreeVO dirTreeVO : trees) {
            if (dirTreeVO.getType().equals(DirTreeVO.Type.DIR)) {
                if (CollectionUtils.isNotEmpty(dirTreeVO.getChildren())) {
                    getConnInfo(dirTreeVO.getChildren(), cons);
                }
                List<DirTreeVO> tempJobDirVOS = cons.stream().filter(dirTreeVO1 -> dirTreeVO1.getParentId().equals(dirTreeVO.getId())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(tempJobDirVOS)) {
                    if (dirTreeVO.getChildren() == null) {
                        dirTreeVO.setChildren(new ArrayList<>(tempJobDirVOS));
                    } else {
                        dirTreeVO.getChildren().addAll(tempJobDirVOS);
                    }
                }
            }

        }
    }

    @Override
    public List<DirTreeVO> getDirTree() {
        return TreeUtils.getTreeList(null, this.directoryMapper.getDirTree());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void move(Long resId, DirTreeVO.Type resType, Long targetId) {
        if (DirTreeVO.Type.DIR.equals(resType)) {
            Directory directory = new Directory();
            directory.setId(resId);
            directory.setParentId(targetId);
            this.directoryMapper.updateById(directory);
            return;
        }
        this.relationService.deleteByTargetId(resId, RelationType.DIR_CONNECTION);
        Relation relation = new Relation();
        relation.setResId(resId);
        relation.setTargetId(targetId);
        relation.setType(RelationType.DIR_CONNECTION.name());
        this.relationService.save(relation);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(DirectoryDTO directoryDTO) {
        Directory directory = new Directory();
        BeanUtils.copyProperties(directoryDTO, directory);
        directory.setId(null);
        this.directoryMapper.insert(directory);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(DirectoryDTO directoryDTO) {
        Directory directory = new Directory();
        directory.setId(directoryDTO.getId());
        directory.setName(directoryDTO.getName());
        this.directoryMapper.updateById(directory);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteById(Long dirId) {
        List<DirTreeVO> dirTreeVOS = TreeUtils.getTreeList(dirId, this.directoryMapper.getDirTree());
        if (CollectionUtils.isNotEmpty(dirTreeVOS)) {
            dirTreeVOS.forEach(this::removeSubDir);
        }
        this.directoryMapper.deleteById(dirId);
        this.relationService.deleteByResId(dirId, RelationType.DIR_CONNECTION);
//        return true;
    }

    private void removeSubDir(DirTreeVO dirTreeVO) {
        if (dirTreeVO.getType().equals(DirTreeVO.Type.DIR)) {
            this.directoryMapper.deleteById(dirTreeVO.getId());
            this.relationService.deleteByResId(dirTreeVO.getId(), RelationType.DIR_CONNECTION);
        }
        if (dirTreeVO.getType().equals(DirTreeVO.Type.CONN)) {
            connectionService.deleteById(dirTreeVO.getId());
        }
        if (CollectionUtils.isNotEmpty(dirTreeVO.getChildren())) {
            dirTreeVO.getChildren().forEach(this::removeSubDir);
        }
    }
}
